"""
参数配置管理模块
"""
from typing import Dict, List, Any, Optional
import json
import os
from datetime import datetime

from models.parameter import Parameter, ParameterGroup
from models.scene import Scene


class ParameterManager:
    """
    参数管理器，负责参数的创建、编辑、验证等操作
    """
    
    def __init__(self, config_path: str = "config/parameters"):
        """
        初始化参数管理器
        
        Args:
            config_path: 参数配置文件路径
        """
        self.config_path = config_path
        os.makedirs(config_path, exist_ok=True)
        
        # 加载默认参数模板
        self.parameter_templates = self._load_parameter_templates()
    
    def get_parameters_for_scene_type(self, scene_type: str) -> List[ParameterGroup]:
        """
        获取指定场景类型的参数组
        
        Args:
            scene_type: 场景类型
            
        Returns:
            参数组列表
        """
        if scene_type in self.parameter_templates:
            return self.parameter_templates[scene_type]
        else:
            # 返回通用参数组
            return self.parameter_templates.get("common", [])
    
    def validate_parameters(self, scene_type: str, parameters: Dict[str, Any]) -> Dict[str, str]:
        """
        验证参数值是否符合要求
        
        Args:
            scene_type: 场景类型
            parameters: 参数值字典
            
        Returns:
            错误信息字典，键为参数名，值为错误信息，如果没有错误则为空字典
        """
        errors = {}
        parameter_groups = self.get_parameters_for_scene_type(scene_type)
        
        # 遍历所有参数组和参数
        for group in parameter_groups:
            for param in group.parameters:
                param_name = param.name
                
                # 检查必填参数
                if param.required and (param_name not in parameters or parameters[param_name] is None):
                    errors[param_name] = "此参数为必填项"
                    continue
                
                # 如果参数不存在，跳过后续验证
                if param_name not in parameters:
                    continue
                
                value = parameters[param_name]
                
                # 类型验证
                if param.param_type == "number":
                    try:
                        float_value = float(value)
                        
                        # 范围验证
                        if param.min_value is not None and float_value < param.min_value:
                            errors[param_name] = f"值不能小于 {param.min_value}"
                        if param.max_value is not None and float_value > param.max_value:
                            errors[param_name] = f"值不能大于 {param.max_value}"
                    except (ValueError, TypeError):
                        errors[param_name] = "请输入有效的数字"
                
                elif param.param_type == "string":
                    if not isinstance(value, str):
                        errors[param_name] = "请输入文本"
                    elif param.min_length is not None and len(value) < param.min_length:
                        errors[param_name] = f"文本长度不能小于 {param.min_length} 个字符"
                    elif param.max_length is not None and len(value) > param.max_length:
                        errors[param_name] = f"文本长度不能大于 {param.max_length} 个字符"
                
                elif param.param_type == "boolean":
                    if not isinstance(value, bool):
                        errors[param_name] = "请选择是或否"
                
                elif param.param_type == "select":
                    if param.options and value not in [opt["value"] for opt in param.options]:
                        errors[param_name] = "请选择有效的选项"
        
        return errors
    
    def apply_parameters_to_scene(self, scene: Scene, parameters: Dict[str, Any]) -> Scene:
        """
        将参数应用到场景中
        
        Args:
            scene: 场景对象
            parameters: 参数值字典
            
        Returns:
            更新后的场景对象
        """
        # 验证参数
        errors = self.validate_parameters(scene.scene_type, parameters)
        if errors:
            error_msg = "; ".join([f"{k}: {v}" for k, v in errors.items()])
            raise ValueError(f"参数验证失败: {error_msg}")
        
        # 更新场景参数
        scene.parameters = parameters
        scene.updated_at = datetime.now().isoformat()
        
        return scene
    
    def get_parameter_defaults(self, scene_type: str) -> Dict[str, Any]:
        """
        获取指定场景类型的默认参数值
        
        Args:
            scene_type: 场景类型
            
        Returns:
            默认参数值字典
        """
        defaults = {}
        parameter_groups = self.get_parameters_for_scene_type(scene_type)
        
        # 遍历所有参数组和参数
        for group in parameter_groups:
            for param in group.parameters:
                if param.default_value is not None:
                    defaults[param.name] = param.default_value
        
        return defaults
    
    def create_custom_parameter(self, scene: Scene, param_name: str, param_type: str, 
                               default_value: Any = None, description: str = "") -> Scene:
        """
        为场景创建自定义参数
        
        Args:
            scene: 场景对象
            param_name: 参数名称
            param_type: 参数类型
            default_value: 默认值
            description: 参数描述
            
        Returns:
            更新后的场景对象
        """
        # 确保自定义参数组存在
        if "custom_parameters" not in scene.parameters:
            scene.parameters["custom_parameters"] = {}
        
        # 添加自定义参数
        scene.parameters["custom_parameters"][param_name] = {
            "type": param_type,
            "value": default_value,
            "description": description
        }
        
        scene.updated_at = datetime.now().isoformat()
        
        return scene
    
    def _load_parameter_templates(self) -> Dict[str, List[ParameterGroup]]:
        """
        加载参数模板
        
        Returns:
            参数模板字典，键为场景类型，值为参数组列表
        """
        # 检查配置文件是否存在
        template_path = os.path.join(self.config_path, "parameter_templates.json")
        if os.path.exists(template_path):
            with open(template_path, 'r', encoding='utf-8') as f:
                templates_data = json.load(f)
                
            # 将JSON数据转换为ParameterGroup和Parameter对象
            templates = {}
            for scene_type, groups_data in templates_data.items():
                groups = []
                for group_data in groups_data:
                    parameters = []
                    for param_data in group_data["parameters"]:
                        parameters.append(Parameter(**param_data))
                    
                    group = ParameterGroup(
                        id=group_data["id"],
                        name=group_data["name"],
                        description=group_data.get("description", ""),
                        parameters=parameters
                    )
                    groups.append(group)
                
                templates[scene_type] = groups
                
            return templates
        else:
            # 如果配置文件不存在，创建默认模板
            templates = self._create_default_templates()
            
            # 保存默认模板
            self._save_parameter_templates(templates)
            
            return templates
    
    def _create_default_templates(self) -> Dict[str, List[ParameterGroup]]:
        """
        创建默认参数模板
        
        Returns:
            默认参数模板字典
        """
        templates = {}
        
        # 通用参数组
        common_params = [
            Parameter(
                name="time_period",
                display_name="测算时间段",
                description="选择测算的时间单位",
                param_type="select",
                required=True,
                default_value="monthly",
                options=[
                    {"label": "月度", "value": "monthly"},
                    {"label": "季度", "value": "quarterly"},
                    {"label": "年度", "value": "yearly"}
                ]
            ),
            Parameter(
                name="currency",
                display_name="货币单位",
                description="选择测算使用的货币单位",
                param_type="select",
                required=True,
                default_value="CNY",
                options=[
                    {"label": "人民币 (CNY)", "value": "CNY"},
                    {"label": "美元 (USD)", "value": "USD"},
                    {"label": "欧元 (EUR)", "value": "EUR"}
                ]
            ),
            Parameter(
                name="tax_rate",
                display_name="税率",
                description="适用的税率百分比",
                param_type="number",
                required=True,
                default_value=0.13,
                min_value=0,
                max_value=1,
                step=0.01
            )
        ]
        
        common_group = ParameterGroup(
            id="common",
            name="基础参数",
            description="通用基础参数设置",
            parameters=common_params
        )
        
        templates["common"] = [common_group]
        
        # 销售预测参数
        sales_forecast_params = [
            Parameter(
                name="growth_rate",
                display_name="增长率",
                description="预期的销售增长率",
                param_type="number",
                required=True,
                default_value=0.05,
                min_value=-0.5,
                max_value=2,
                step=0.01
            ),
            Parameter(
                name="forecast_periods",
                display_name="预测周期数",
                description="需要预测的周期数量",
                param_type="number",
                required=True,
                default_value=12,
                min_value=1,
                max_value=60,
                step=1
            ),
            Parameter(
                name="seasonality",
                display_name="考虑季节性",
                description="是否在预测中考虑季节性因素",
                param_type="boolean",
                required=False,
                default_value=False
            )
        ]
        
        sales_forecast_group = ParameterGroup(
            id="sales_forecast",
            name="销售预测参数",
            description="销售预测相关参数设置",
            parameters=sales_forecast_params
        )
        
        templates["sales_forecast"] = [common_group, sales_forecast_group]
        
        # 投资回报分析参数
        investment_params = [
            Parameter(
                name="initial_investment",
                display_name="初始投资额",
                description="项目的初始投资金额",
                param_type="number",
                required=True,
                default_value=100000,
                min_value=0
            ),
            Parameter(
                name="discount_rate",
                display_name="折现率",
                description="用于计算净现值的折现率",
                param_type="number",
                required=True,
                default_value=0.08,
                min_value=0,
                max_value=1,
                step=0.01
            ),
            Parameter(
                name="project_years",
                display_name="项目年限",
                description="投资项目的预期年限",
                param_type="number",
                required=True,
                default_value=5,
                min_value=1,
                max_value=50,
                step=1
            ),
            Parameter(
                name="estimated_annual_return",
                display_name="估计年回报率",
                description="如果没有详细现金流数据，使用此估计值",
                param_type="number",
                required=False,
                default_value=0.15,
                min_value=-1,
                max_value=10,
                step=0.01
            )
        ]
        
        investment_group = ParameterGroup(
            id="investment",
            name="投资参数",
            description="投资回报分析相关参数设置",
            parameters=investment_params
        )
        
        templates["investment_return"] = [common_group, investment_group]
        
        # 成本测算参数
        cost_params = [
            Parameter(
                name="production_volume",
                display_name="生产数量",
                description="计划生产的产品数量",
                param_type="number",
                required=True,
                default_value=1000,
                min_value=1
            )
        ]
        
        cost_group = ParameterGroup(
            id="cost",
            name="成本参数",
            description="成本测算相关参数设置",
            parameters=cost_params
        )
        
        templates["cost_analysis"] = [common_group, cost_group]
        
        # 利润预测参数
        profit_params = [
            Parameter(
                name="forecast_periods",
                display_name="预测周期数",
                description="需要预测的周期数量",
                param_type="number",
                required=True,
                default_value=12,
                min_value=1,
                max_value=60,
                step=1
            ),
            Parameter(
                name="revenue_growth_rate",
                display_name="收入增长率",
                description="预期的收入增长率",
                param_type="number",
                required=True,
                default_value=0.05,
                min_value=-0.5,
                max_value=2,
                step=0.01
            ),
            Parameter(
                name="cost_growth_rate",
                display_name="成本增长率",
                description="预期的成本增长率",
                param_type="number",
                required=True,
                default_value=0.03,
                min_value=-0.5,
                max_value=2,
                step=0.01
            )
        ]
        
        profit_group = ParameterGroup(
            id="profit",
            name="利润参数",
            description="利润预测相关参数设置",
            parameters=profit_params
        )
        
        templates["profit_projection"] = [common_group, profit_group]
        
        # 自定义测算参数
        custom_params = [
            Parameter(
                name="custom_formula",
                display_name="自定义计算公式",
                description="使用Python代码编写自定义计算逻辑，必须生成一个名为'result'的变量",
                param_type="string",
                required=True,
                default_value="# 示例: 计算总和\nresult = sum(data['values']['amount'])",
                multiline=True
            )
        ]
        
        custom_group = ParameterGroup(
            id="custom",
            name="自定义参数",
            description="自定义测算相关参数设置",
            parameters=custom_params
        )
        
        templates["custom"] = [common_group, custom_group]
        
        return templates
    
    def _save_parameter_templates(self, templates: Dict[str, List[ParameterGroup]]) -> None:
        """
        保存参数模板到文件
        
        Args:
            templates: 参数模板字典
        """
        # 将ParameterGroup和Parameter对象转换为可序列化的字典
        templates_data = {}
        for scene_type, groups in templates.items():
            groups_data = []
            for group in groups:
                parameters_data = []
                for param in group.parameters:
                    parameters_data.append(param.dict())
                
                groups_data.append({
                    "id": group.id,
                    "name": group.name,
                    "description": group.description,
                    "parameters": parameters_data
                })
            
            templates_data[scene_type] = groups_data
        
        # 保存到文件
        template_path = os.path.join(self.config_path, "parameter_templates.json")
        os.makedirs(os.path.dirname(template_path), exist_ok=True)
        
        with open(template_path, 'w', encoding='utf-8') as f:
            json.dump(templates_data, f, ensure_ascii=False, indent=2)